import { HttpException, HttpStatus, Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Not, Repository } from "typeorm";
import * as ExcelJS from "exceljs";
import { ApiDto } from "./dto/api.dto";
import { SearchApiDto } from "./dto/search-api.dto";
import { ApiEntity } from "./entities/api.entity";
import * as crypto from "crypto-js";
import { toEntity } from "src/utils/dto2Entity";
import { PageResponseResult } from "src/common/tools/page.response.result";
import { TenantService } from "@/modules/tenant/tenant.service";

/*
 *@Description: 接口管理模块业务
 *返回接口数据时，排除掉超级管理员,超级管理员id为0，默认管理员接口名为administrator。切记
 *@Author: 土豆哥
 *@Date: 2022-11-28 22:20:27
 */
@Injectable()
export class ApiService {
  constructor(private readonly tenantService: TenantService) {}
  @InjectRepository(ApiEntity)
  private readonly apiRepository: Repository<ApiEntity>;

  /**
   * 获取接口分页列表
   * @param searchApiDto 搜索dto
   */
  async getApiPageList(tenantId: number, searchApiDto: SearchApiDto) {
    const { page, keyword } = searchApiDto;
    const { current, size } = page;
    const skip = (current - 1) * size;
    const tenantRepository = await this.getTenantRepository(tenantId);
    const queryBuilder = tenantRepository.createQueryBuilder();
    queryBuilder.where("id<>0");
    if (keyword) {
      queryBuilder.andWhere(`api_name=:apiName`, { apiName: keyword });
      queryBuilder.orWhere(`phone=:phone`, { phone: keyword });
    }
    const entities = await queryBuilder
      .orderBy("create_time", "DESC")
      .offset(skip)
      .limit(size)
      .getMany();

    page.total = await queryBuilder.getCount();
    const result = new PageResponseResult<ApiEntity[]>(page.total, entities);
    return result;
  }

  /**
   * 获取接口列表
   */
  async getApiList(tenantId: number) {
    const tenantRepository = await this.getTenantRepository(tenantId);
    const entities = await tenantRepository.find({
      where: {
        id: Not(0),
      },
    });
    return entities;
  }

  /**
   * 根据接口id获取接口信息
   * @param id 编号
   */
  async getApiById(tenantId: number, id: number) {
    const entity = await this.getById(tenantId, id);
    return entity;
  }

  /**
   * 根据接口名称获取接口信息
   * @param apiName 接口名称
   */
  async getApiByApiName(tenantId: number, apiName: string) {
    const tenantRepository = await this.getTenantRepository(tenantId);
    const entity = await tenantRepository.findOneBy({
      apiName,
    });
    return entity;
  }

  /**
   * 创建接口
   * @param apiDto 接口dto
   */
  async createApi(tenantId: number, apiDto: ApiDto) {
    const tenantRepository = await this.getTenantRepository(tenantId);
    const api = await tenantRepository.findOneBy({
      apiName: apiDto.apiName,
    });
    if (api) {
      throw new HttpException(
        {
          message: "操作失败,接口名已使用.",
        },
        HttpStatus.BAD_REQUEST
      );
    }
    const apiEntity = new ApiEntity();
    toEntity(apiDto, apiEntity);
    apiEntity.createTime = new Date();
    await tenantRepository.insert(apiEntity);
  }

  /**
   * 修改接口
   * @param id 编号
   * @param apiDto 接口dto
   */
  async updateApiById(tenantId: number, id: number, apiDto: ApiDto) {
    const api = await this.getById(tenantId, id);
    if (!api) {
      throw new HttpException(
        {
          message: "操作失败,未找到接口信息.",
        },
        HttpStatus.BAD_REQUEST
      );
    }
    const apiEntity = new ApiEntity();
    toEntity(apiDto, apiEntity);
    const tenantRepository = await this.getTenantRepository(tenantId);
    await tenantRepository.update(id, apiEntity);
  }

  /**
   * 删除接口
   * @param id 编号
   */
  async removeApiById(tenantId: number, id: number) {
    const tenantRepository = await this.getTenantRepository(tenantId);
    await tenantRepository.delete(id);
  }

  /**
   * 批量删除接口
   * @param id 编号
   */
  async removeApiByIds(tenantId: number, ids: string) {
    const arr = ids.split(",");
    const tenantRepository = await this.getTenantRepository(tenantId);
    await tenantRepository.delete(arr);
  }

  private async getById(tenantId: number, id: number) {
    const tenantRepository = await this.getTenantRepository(tenantId);
    return await tenantRepository.findOne({
      where: {
        id,
      },
    });
  }
  private async getTenantRepository(
    tenantId: number
  ): Promise<Repository<ApiEntity>> {
    const tenantConnection = await this.tenantService.getTenantConnection(
      tenantId
    );
    return tenantConnection.getRepository(ApiEntity);
  }
}
